home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 October: Mac OS SDK / Dev.CD Oct 96 SDK / Dev.CD Oct 96 SDK2.toast / Development Kits (Disc 2) / OpenDoc Development Framework / ODFDev / ODF / Found / FWString / Sources / SLCharIt.cpp < prev    next >
Encoding:
Text File  |  1996-08-16  |  22.2 KB  |  701 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                SLCharIt.cpp
  4. //    Release Version:    $ ODF 1 $
  5. //
  6. //    Copyright:    (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #include "FWFound.hpp"
  11.  
  12. #ifndef SLCHARIT_H
  13. #include "SLCharIt.h"
  14. #endif
  15.  
  16. #ifndef PRCHARIT_H
  17. #include "PRCharIt.h"
  18. #endif
  19.  
  20. #ifndef SOM_FW_OTextRunReader_xh
  21. #include "SLTxtRun.xh"
  22. #endif
  23.  
  24. #ifdef FW_BUILD_MAC
  25. #pragma segment Strings
  26. #endif
  27.  
  28. //========================================================================================
  29. // Error handling strategy:
  30. //
  31. //    This unit provides interfaces that are exported from a shared library.
  32. //  As such, these interfaces must catch all exceptions and turn them into error codes.
  33. //
  34. //    Most functions in this unit only call functions that are known to not throw exceptions.
  35. //  For these functions, we do not use a try block, but instead simply check the error
  36. //  codes and return if any error is seen during the execution of the function. 
  37. //
  38. //    A few functions in this unit do call functions that can throw exceptions.  Two
  39. //    possibilities must be considered:
  40. //
  41. //    1) The function calls a SOM member function.  We assume that the SOM C++ binding will 
  42. //    invoke our SOMCHKEXCEPT which will throw an exception.
  43. //
  44. //    2) The function calls ::operator new.  We assume that operator new will throw an
  45. //    exception if the allocation fails.
  46. //
  47. //    There should be no other way for exceptions to be raised.  Functions defined here that
  48. //  can raise exceptions via 1) or 2) above must be enclosed in a try block.  We use the
  49. //    FW_SOM_TRY macros which will convert the exception into an Environment error.
  50. //========================================================================================
  51.  
  52. //----------------------------------------------------------------------------------------
  53. //    ByteInBlock
  54. //----------------------------------------------------------------------------------------
  55.  
  56. inline FW_ByteCount BytesInBlock(const char* last, const char* first)
  57. {
  58.     return last - first;
  59. }
  60.  
  61. //----------------------------------------------------------------------------------------
  62. //    PreviousByte
  63. //----------------------------------------------------------------------------------------
  64.  
  65. inline const char* PreviousByte(const char* current, FW_ByteCount delta)
  66. {
  67.     return current - delta;
  68. }
  69.  
  70. //----------------------------------------------------------------------------------------
  71. //    ClassInvariants
  72. //----------------------------------------------------------------------------------------
  73.  
  74. #ifdef FW_DEBUG
  75. static void ClassInvariants(FW_HTextReader self)
  76. {
  77.     if (self->fNext == 0)
  78.     {
  79.         // Must be in initial state, before first GetNextBuffer
  80.         FW_PRIV_ASSERT(self->fStart == 0);
  81.         FW_PRIV_ASSERT(self->fLimit == 0);
  82.         FW_PRIV_ASSERT(self->fBufferSum == 0);        
  83.     }
  84.     else if (self->fNext == self->fLimit)
  85.     {
  86.         // Must be at end of data structure
  87.         FW_PRIV_ASSERT(self->fBufferSum == self->fByteLength);
  88.     }
  89.     else
  90.     {
  91.         FW_PRIV_ASSERT(self->fBufferSum < self->fByteLength);
  92.         if (self->fNext < self->fStart)
  93.         {
  94.             // Must be at position -1 (backup past beginning)
  95.             FW_PRIV_ASSERT(self->fBufferSum == 0);
  96.             FW_PRIV_ASSERT(self->fNext == self->fStart-1); // may not be correct anymore
  97.         }
  98.         else
  99.         {
  100.             // Must be somewhere in middle of stream
  101.             FW_PRIV_ASSERT(self->fStart <= self->fNext);
  102.             FW_PRIV_ASSERT(self->fNext <= self->fLimit);
  103.         }
  104.     }
  105. }
  106. #else
  107. inline void ClassInvariants(FW_HTextReader) {}
  108.     // Let optimizer remove empty inline
  109. #endif
  110.  
  111. //----------------------------------------------------------------------------------------
  112. //    TextReader_Initialize
  113. //----------------------------------------------------------------------------------------
  114.  
  115. static void TextReader_Initialize(FW_HTextReader self, 
  116.                                 Environment *ev,
  117.                                 FW_OTextRunReader* adoptedReader)
  118. {
  119.     FW_SOM_TRY
  120.     {
  121.         FW_ByteCount length;
  122.         FW_Locale locale;
  123.         const char* start = adoptedReader->GetCurrentRun(ev, &length, &locale); // may throw
  124.         self->fLocale = locale;
  125.         self->fReader = adoptedReader;
  126.         self->fStart = start;
  127.         self->fLimit = self->fStart+length;
  128.         self->fNext = self->fStart;
  129.         self->fByteLength = self->fReader->GetTotalLength(ev); // may throw
  130.         ClassInvariants(self);
  131.     }
  132.     FW_SOM_CATCH
  133. }
  134.  
  135. //----------------------------------------------------------------------------------------
  136. //    FW_PrivTextReader_Initialize
  137. //----------------------------------------------------------------------------------------
  138.  
  139. FW_HTextReader FW_PrivTextReader_New(Environment *ev, FW_OTextRunReader* adoptedReader)
  140. {
  141.     FW_SOM_TRY
  142.     {
  143.         FW_HTextReader self = new FW_SPrivTextReader;    // may throw
  144.         self->fReader = 0;
  145.         self->fStart = 0;
  146.         self->fLimit = 0;
  147.         self->fNext = 0;
  148.         self->fByteLength = 0;
  149.         self->fBufferSum = 0;
  150.         self->fLocale.fScriptCode = 0;
  151.         self->fLocale.fLangCode = 0;
  152.         self->fRefCount = 0;
  153.         TextReader_Initialize(self, ev, adoptedReader);
  154.         return self;
  155.     }
  156.     FW_SOM_CATCH
  157.     return 0;
  158. }
  159.  
  160. //----------------------------------------------------------------------------------------
  161. //    FW_PrivTextReader_Acquire
  162. //----------------------------------------------------------------------------------------
  163.  
  164. void FW_PrivTextReader_Acquire(FW_HTextReader self, Environment *ev)
  165. {
  166. FW_UNUSED(ev);
  167.     // No FW_SOM_TRY necessary
  168.     ++self->fRefCount;
  169. }
  170.  
  171. //----------------------------------------------------------------------------------------
  172. //    FW_PrivTextReader_Delete
  173. //----------------------------------------------------------------------------------------
  174.  
  175. void FW_PrivTextReader_Release(FW_HTextReader self, Environment *ev)
  176. {
  177. FW_UNUSED(ev);
  178.     // No FW_SOM_TRY necessary
  179.     if (--self->fRefCount == 0)
  180.         delete self;
  181. }
  182.  
  183. //----------------------------------------------------------------------------------------
  184. //    FW_PrivTextReader_GetCharacterAndAdvance
  185. //----------------------------------------------------------------------------------------
  186.  
  187. FW_LChar FW_PrivTextReader_GetCharacterAndAdvance(FW_HTextReader self, Environment *ev, FW_ByteCount* bytesInChar)
  188. {
  189.     // No FW_SOM_TRY necessary
  190.     ClassInvariants(self);
  191.     FW_ByteCount b;
  192.     if (!bytesInChar)
  193.         bytesInChar = &b;
  194.     FW_LChar temp = FW_PrivTextReader_PeekCharacter(self, bytesInChar);
  195.     if (temp != FW_kNulCharacter)
  196.         FW_PrivTextReader_Advance(self, ev, *bytesInChar);
  197.     ClassInvariants(self);
  198.     return temp;
  199. }
  200.  
  201. //----------------------------------------------------------------------------------------
  202. //    FW_PrivTextReader_Advance
  203. //----------------------------------------------------------------------------------------
  204.  
  205. void FW_PrivTextReader_Advance(FW_HTextReader self, Environment *ev, FW_ByteCount delta)
  206. {
  207.     // No FW_SOM_TRY necessary
  208.     ClassInvariants(self);
  209.     FW_PRIV_ASSERT(delta>=0);
  210.     FW_PRIV_ASSERT(delta+FW_PrivTextReader_GetPosition(self) <= self->fByteLength);
  211.     FW_ByteCount inThisBuf = BytesInBlock(self->fLimit, self->fNext);
  212.     while (delta >= inThisBuf)
  213.     {
  214.         delta -= inThisBuf;
  215.         self->fNext += inThisBuf;
  216.         FW_PrivTextReader_GetNextBuffer(self, ev);
  217.         if (FW_GetEvError(ev))
  218.             return;
  219.         inThisBuf = BytesInBlock(self->fLimit, self->fStart);
  220.     }
  221.     self->fNext += delta;
  222.     ClassInvariants(self);
  223. }
  224.  
  225. //----------------------------------------------------------------------------------------
  226. //    FW_PrivTextReader_PeekCharacter
  227. //----------------------------------------------------------------------------------------
  228.  
  229. FW_LChar FW_PrivTextReader_PeekCharacter(FW_HTextReader self, FW_ByteCount* bytesInChar)
  230. {
  231.     // No FW_SOM_TRY necessary, no error possible
  232.     ClassInvariants(self);
  233.  
  234.     // assume 1 byte per character for now
  235.     if (bytesInChar)
  236.         *bytesInChar = kTempHackOneBytePerCharacter;
  237.  
  238.     if (self->fNext>=self->fStart && self->fNext<self->fLimit)
  239.     {
  240.         FW_LChar ch = *self->fNext;    // default to one byte characters
  241.         return ch;
  242.     }
  243.     else
  244.         return FW_kNulCharacter;
  245. }
  246.  
  247. //----------------------------------------------------------------------------------------
  248. //    FW_PrivTextReader_GetPosition
  249. //----------------------------------------------------------------------------------------
  250.  
  251. FW_ByteCount FW_PrivTextReader_GetPosition(FW_HTextReader self)
  252. {
  253.     // No FW_SOM_TRY necessary, no error possible
  254.     ClassInvariants(self);
  255.     FW_ByteCount result;
  256.  
  257.     if (self->fNext == self->fLimit)
  258.         result = self->fBufferSum;
  259.     else
  260.         result = self->fBufferSum + (self->fNext - self->fStart);
  261.  
  262.     return result;
  263. }
  264.  
  265. //----------------------------------------------------------------------------------------
  266. //    DelegateGetNextBuffer
  267. //----------------------------------------------------------------------------------------
  268.  
  269. static void DelegateGetNextBuffer(FW_HTextReader self, Environment* ev)
  270. {
  271.     FW_SOM_TRY
  272.     {
  273.         FW_ByteCount length;
  274.         if (self->fReader->NextRun(ev))    // may throw
  275.         {
  276.             FW_Locale locale;
  277.             const char* start = self->fReader->GetCurrentRun(ev, &length, &locale); // may throw
  278.             self->fStart = start;
  279.             self->fLimit = start + length;
  280.             self->fLocale = locale;
  281.         }
  282.         else
  283.         {
  284.             self->fStart = 0;
  285.             self->fLimit = 0;
  286.         }
  287.     }
  288.     FW_SOM_CATCH
  289. }
  290.  
  291. //----------------------------------------------------------------------------------------
  292. //    FW_PrivTextReader_GetNextBuffer
  293. //----------------------------------------------------------------------------------------
  294.  
  295. void FW_PrivTextReader_GetNextBuffer(FW_HTextReader self, Environment *ev)
  296. {
  297.     // No FW_SOM_TRY necessary
  298.     // ClassInvariants won't hold here.
  299.     // This function is called to (among other things) restore class invariants.
  300.     FW_PRIV_ASSERT(self->fNext == self->fLimit);    // Must hold, but violates invariants
  301.     self->fBufferSum += BytesInBlock(self->fLimit, self->fStart);
  302.     if (self->fBufferSum < self->fByteLength)
  303.     {
  304.         DelegateGetNextBuffer(self, ev);
  305.         if (FW_GetEvError(ev))
  306.             return;
  307.         self->fNext = self->fStart;
  308.     }
  309.     else
  310.     {
  311.         FW_PRIV_ASSERT(self->fBufferSum == self->fByteLength);
  312.         self->fNext = self->fLimit;
  313.     }
  314.     ClassInvariants(self);
  315. }
  316.  
  317. //----------------------------------------------------------------------------------------
  318. //    FW_PrivTextReader_BackupAndGetCharacter
  319. //----------------------------------------------------------------------------------------
  320.  
  321. FW_LChar FW_PrivTextReader_BackupAndGetCharacter(FW_HTextReader self, Environment *ev, FW_ByteCount* bytesInChar)
  322. {
  323.     // No FW_SOM_TRY necessary
  324.     ClassInvariants(self);
  325.     // assume 1 byte per character for now
  326.     FW_PrivTextReader_Backup(self, ev, kTempHackOneBytePerCharacter);
  327.     if (FW_GetEvError(ev))
  328.         return 0;
  329.     ClassInvariants(self);
  330.     return FW_PrivTextReader_PeekCharacter(self, bytesInChar);
  331. }
  332.  
  333. //----------------------------------------------------------------------------------------
  334. //    FW_PrivTextReader_Backup
  335. //----------------------------------------------------------------------------------------
  336.  
  337. void FW_PrivTextReader_Backup(FW_HTextReader self, Environment *ev, FW_ByteCount delta)
  338. {
  339.     // No FW_SOM_TRY necessary
  340.     ClassInvariants(self);
  341.     FW_PRIV_ASSERT(delta>=0);
  342. /*    FW_PRIV_ASSERT(delta<=GetPosition());    * doesn't allow backup at start */
  343.  
  344.     if (delta > 0)
  345.     {
  346.         if (self->fNext==self->fStart)    // at the start of a buffer
  347.         {
  348.             FW_PrivTextReader_GetPreviousBuffer(self, ev);
  349.             if (FW_GetEvError(ev))
  350.                 return;
  351.         }
  352.         else if (self->fNext == self->fLimit)    // at the end of the last buffer
  353.         {    // subtract bytes that were added by GetNextBuffer
  354.             self->fBufferSum -= BytesInBlock(self->fLimit, self->fStart);
  355.         }
  356.  
  357.         FW_ByteCount inThisBuf = BytesInBlock(self->fNext, self->fStart);
  358.         if (inThisBuf > 0)
  359.             while (delta > inThisBuf)
  360.             {
  361.                 delta -= inThisBuf;
  362.                 self->fNext = self->fStart;
  363.                 FW_PrivTextReader_GetPreviousBuffer(self, ev);
  364.                 if (FW_GetEvError(ev))
  365.                     return;
  366.                 inThisBuf = BytesInBlock(self->fNext, self->fStart);
  367.             }
  368.         self->fNext = PreviousByte(self->fNext, delta);    // may backup before fStart (-1)
  369.         ClassInvariants(self);
  370.     }
  371. }
  372.  
  373. //----------------------------------------------------------------------------------------
  374. //    DelegateGetPreviousBuffer
  375. //----------------------------------------------------------------------------------------
  376.  
  377. static void DelegateGetPreviousBuffer(FW_HTextReader self, Environment *ev)
  378. {
  379.     FW_SOM_TRY
  380.     {
  381.         FW_ByteCount length;
  382.         if (self->fReader->PreviousRun(ev)) // may throw
  383.         {
  384.             FW_Locale locale;
  385.             const char* start = self->fReader->GetCurrentRun(ev, &length, &locale); // may throw
  386.             self->fStart = start;
  387.             self->fLimit = start+length;
  388.             self->fLocale = locale;
  389.         }
  390.         else
  391.         {
  392.             self->fStart = 0;
  393.             self->fLimit = 0;
  394.         }
  395.     }
  396.     FW_SOM_CATCH
  397. }
  398.  
  399.  
  400. //----------------------------------------------------------------------------------------
  401. //    FW_PrivTextReader_GetPreviousBuffer
  402. //----------------------------------------------------------------------------------------
  403.  
  404. void FW_PrivTextReader_GetPreviousBuffer(FW_HTextReader self, Environment *ev)
  405. {
  406.     // No FW_SOM_TRY necessary
  407.     ClassInvariants(self);
  408.     if (self->fBufferSum == 0)
  409.     {
  410.         self->fNext = self->fStart;
  411.     }
  412.     else if (self->fBufferSum == self->fByteLength)
  413.     {
  414.         FW_PRIV_ASSERT(self->fLimit == self->fNext);
  415.         self->fBufferSum -= BytesInBlock(self->fLimit, self->fStart);
  416.     }
  417.     else
  418.     {
  419.         FW_PRIV_ASSERT(self->fStart == self->fNext);
  420.         DelegateGetPreviousBuffer(self, ev);
  421.         if (FW_GetEvError(ev))
  422.             return;
  423.         FW_PRIV_ASSERT(self->fStart < self->fLimit);
  424.         self->fBufferSum -= BytesInBlock(self->fLimit, self->fStart);
  425.         FW_PRIV_ASSERT(self->fBufferSum >= 0);
  426.         self->fNext = self->fLimit;
  427.     }
  428.     // Invariants won't hold here
  429.     // The calling function must modify fNext appropriately
  430.     // Note that GetPreviousBuffer is a protected method,
  431.     // so clients are not held responsible to restore invariants.
  432.     // Also, subclasses shouldn't need to call this function directly.
  433. }
  434.  
  435. //----------------------------------------------------------------------------------------
  436. //    FW_PrivTextReader_SetPosition
  437. //----------------------------------------------------------------------------------------
  438.  
  439. void FW_PrivTextReader_SetPosition(FW_HTextReader self, Environment *ev, FW_ByteCount position)
  440. {
  441.     // No FW_SOM_TRY necessary
  442.     ClassInvariants(self);
  443.     FW_PRIV_ASSERT(position>=0);
  444.     FW_PRIV_ASSERT(position<=self->fByteLength);
  445.     FW_ByteCount curPosition = FW_PrivTextReader_GetPosition(self);
  446.     if (position < curPosition)
  447.         FW_PrivTextReader_Backup(self, ev, curPosition-position);
  448.     else if (position > curPosition)
  449.         FW_PrivTextReader_Advance(self, ev, position-curPosition);
  450.     ClassInvariants(self);
  451. }
  452.  
  453. //----------------------------------------------------------------------------------------
  454. //    FW_PrivTextReader_GetByteLength
  455. //----------------------------------------------------------------------------------------
  456.  
  457. FW_ByteCount FW_PrivTextReader_GetByteLength(FW_HTextReader self)
  458. {
  459.     // No FW_SOM_TRY necessary
  460.     return self->fByteLength;
  461. }
  462.  
  463. //----------------------------------------------------------------------------------------
  464. //    FW_PrivTextReader_PeekRunAhead
  465. //----------------------------------------------------------------------------------------
  466.  
  467. void FW_PrivTextReader_PeekRunAhead(FW_HTextReader self, const char** start, FW_ByteCount* length)
  468. {
  469.     // No FW_SOM_TRY necessary, no error possible
  470.     *start = self->fNext;
  471.     *length = self->fLimit - self->fNext;
  472. }
  473.  
  474. //----------------------------------------------------------------------------------------
  475. //    FW_PrivTextReader_PeekRunBehind
  476. //----------------------------------------------------------------------------------------
  477.  
  478. void FW_PrivTextReader_PeekRunBehind(FW_HTextReader self, const char** end, FW_ByteCount* length)
  479. {
  480.     // No FW_SOM_TRY necessary, no error possible
  481.     *end = self->fNext;
  482.     *length = self->fNext - self->fStart;
  483. }
  484.  
  485. //----------------------------------------------------------------------------------------
  486. //    FW_PrivTextReader_PeekByte
  487. //----------------------------------------------------------------------------------------
  488.  
  489. const char* FW_PrivTextReader_PeekByte(FW_HTextReader self)
  490. {
  491.     // No FW_SOM_TRY necessary, no error possible
  492.     ClassInvariants(self);
  493.  
  494.     if (self->fNext>=self->fStart && self->fNext<self->fLimit)
  495.         return self->fNext;
  496.     else
  497.         return NULL;
  498. }
  499.  
  500. //========================================================================================
  501. //    FW_SPrivTextWriter Functions
  502. //========================================================================================
  503.  
  504. //----------------------------------------------------------------------------------------
  505. //    TextWriter_Initialize
  506. //----------------------------------------------------------------------------------------
  507.  
  508. static void TextWriter_Initialize(FW_HTextWriter self, Environment *ev, FW_OTextRunWriter* adoptedWriter)
  509. {
  510.     FW_SOM_TRY
  511.     {
  512.         FW_ByteCount length;
  513.         char* start = adoptedWriter->GetCurrentRun(ev, &length);    // may throw
  514.         self->fWriter = adoptedWriter;
  515.         self->fStart = start;
  516.         self->fLimit = start + length;
  517.         self->fNext = start;
  518.     }
  519.     FW_SOM_CATCH
  520. }
  521.  
  522. //----------------------------------------------------------------------------------------
  523. //    FW_SPrivTextWriter_New
  524. //----------------------------------------------------------------------------------------
  525.  
  526. FW_HTextWriter FW_PrivTextWriter_New(Environment *ev, FW_OTextRunWriter* adoptedWriter)
  527. {
  528.     FW_SOM_TRY
  529.     {
  530.         FW_HTextWriter self = new FW_SPrivTextWriter;    // may throw
  531.         self->fWriter = 0;
  532.         self->fStart = 0;
  533.         self->fLimit = 0;
  534.         self->fNext = 0;
  535.         self->fBufferSum = 0;
  536.         self->fLocale.fScriptCode = 0;
  537.         self->fLocale.fLangCode = 0;
  538.         self->fRefCount = 0;
  539.         TextWriter_Initialize(self, ev, adoptedWriter);
  540.         return self;
  541.     }
  542.     FW_SOM_CATCH
  543.     return 0;
  544. }
  545.  
  546. //----------------------------------------------------------------------------------------
  547. //    TextWriter_Delete
  548. //----------------------------------------------------------------------------------------
  549.  
  550. static void TextWriter_Delete(FW_HTextWriter self, Environment *ev)
  551. {
  552.     // No FW_SOM_TRY necessary
  553.     FW_PRIV_ASSERT(self->fNext <= self->fLimit);
  554.     if (self->fStart <  self->fNext)
  555.     {
  556.         FW_PrivTextWriter_FlushBuffer(self, ev);
  557.         if (FW_GetEvError(ev))
  558.             return;
  559.     }
  560.     FW_PRIV_ASSERT(self->fStart == self->fNext);
  561.     delete self;
  562. }
  563.  
  564. //----------------------------------------------------------------------------------------
  565. //    FW_PrivTextWriter_Acquire
  566. //----------------------------------------------------------------------------------------
  567.  
  568. void FW_PrivTextWriter_Acquire(FW_HTextWriter self)
  569. {
  570.     // No FW_SOM_TRY necessary, no error possible
  571.     ++self->fRefCount;
  572. }
  573.  
  574. //----------------------------------------------------------------------------------------
  575. //    FW_PrivTextWriter_Release
  576. //----------------------------------------------------------------------------------------
  577.  
  578. void FW_PrivTextWriter_Release(FW_HTextWriter self, Environment *ev)
  579. {
  580.     // No FW_SOM_TRY necessary
  581.     if (--self->fRefCount == 0)
  582.         TextWriter_Delete(self, ev);
  583. }
  584.  
  585. //----------------------------------------------------------------------------------------
  586. //    FW_PrivTextWriter_SetBufferSum
  587. //----------------------------------------------------------------------------------------
  588.  
  589. void FW_PrivTextWriter_SetBufferSum(FW_HTextWriter self, FW_ByteCount bufferSum)
  590. {
  591.     // No FW_SOM_TRY necessary, no error possible
  592.     self->fBufferSum = bufferSum;
  593. }
  594.     
  595. //----------------------------------------------------------------------------------------
  596. //    FW_PrivTextWriter_FlushBuffer
  597. //----------------------------------------------------------------------------------------
  598.  
  599. void FW_PrivTextWriter_FlushBuffer(FW_HTextWriter self, Environment* ev)
  600. {
  601.     FW_SOM_TRY
  602.     {
  603.         FW_PRIV_ASSERT(self->fNext <= self->fLimit);
  604.         FW_ByteCount bytesToFlush = self->fNext - self->fStart;
  605.         self->fWriter->FlushRun(ev, self->fStart, bytesToFlush);    // may throw
  606.         self->fBufferSum += bytesToFlush;
  607.         self->fStart = self->fNext;        // Mark the bytes as being written
  608.     }
  609.     FW_SOM_CATCH
  610. }
  611.  
  612. //----------------------------------------------------------------------------------------
  613. //    FW_PrivTextWriter_FlushAndGetNextBuffer
  614. //----------------------------------------------------------------------------------------
  615.  
  616. void FW_PrivTextWriter_FlushAndGetNextBuffer(FW_HTextWriter self, Environment* ev)
  617. {
  618.     FW_SOM_TRY
  619.     {
  620.         FW_ByteCount length;
  621.         FW_PrivTextWriter_FlushBuffer(self, ev);        // flush entire buffer
  622.         self->fWriter->FlushRun(ev, self->fStart, self->fNext - self->fStart);    // may throw
  623.         self->fWriter->NewRun(ev, &self->fLocale);    // may throw
  624.         self->fStart = self->fWriter->GetCurrentRun(ev, &length);    // may throw
  625.         self->fLimit = self->fStart + length;
  626.         self->fNext = self->fStart;
  627.     }
  628.     FW_SOM_CATCH
  629. }
  630.  
  631. //----------------------------------------------------------------------------------------
  632. //    FW_PrivTextWriter_PutCharacterAndAdvance
  633. //----------------------------------------------------------------------------------------
  634.  
  635. void FW_PrivTextWriter_PutCharacterAndAdvance(FW_HTextWriter self, 
  636.                                             Environment *ev, 
  637.                                             FW_LChar character, 
  638.                                             FW_ByteCount bytesInChar)
  639. {
  640.     // No FW_SOM_TRY necessary
  641.     if (self->fNext >= self->fLimit)
  642.     {
  643.         FW_PrivTextWriter_FlushAndGetNextBuffer(self, ev);
  644.         if (FW_GetEvError(ev))
  645.             return;
  646.     }
  647.  
  648.     // assume 1 byte per character for now
  649.     if (bytesInChar == 0)
  650.         bytesInChar = kTempHackOneBytePerCharacter;
  651.  
  652.     FW_PRIV_ASSERT(bytesInChar == 1);
  653.     *self->fNext  = (FW_Char) character;
  654.  
  655.     self->fNext += bytesInChar;
  656. }
  657.  
  658. //----------------------------------------------------------------------------------------
  659. //    FW_PrivTextWriter_GetPosition
  660. //----------------------------------------------------------------------------------------
  661.  
  662. FW_ByteCount FW_PrivTextWriter_GetPosition(FW_HTextWriter self, Environment *ev)
  663. {
  664. FW_UNUSED(ev);
  665.     // No FW_SOM_TRY necessary, no error possible
  666.     return self->fBufferSum + (self->fNext - self->fStart);
  667. }
  668.  
  669. //----------------------------------------------------------------------------------------
  670. //    FW_PrivTextWriter_WritePeek
  671. //----------------------------------------------------------------------------------------
  672.  
  673. void FW_PrivTextWriter_WritePeek(FW_HTextWriter self, Environment *ev, char** start, FW_ByteCount* length)
  674. {
  675.     // No FW_SOM_TRY necessary
  676.     FW_PRIV_ASSERT(self->fNext <= self->fLimit);
  677.     if (self->fNext == self->fLimit)
  678.     {
  679.         FW_PrivTextWriter_FlushAndGetNextBuffer(self, ev);
  680.         if (FW_GetEvError(ev))
  681.             return;
  682.     }
  683.  
  684.     *start = self->fNext;
  685.     *length = self->fLimit - self->fNext;
  686. }
  687.  
  688. //----------------------------------------------------------------------------------------
  689. //    FW_PrivTextWriter_WritePeekAdvance
  690. //----------------------------------------------------------------------------------------
  691.  
  692. void FW_PrivTextWriter_WritePeekAdvance(FW_HTextWriter self, char* start, FW_ByteCount bytesWritten)
  693. {
  694.     // No FW_SOM_TRY necessary, no error possible
  695.     FW_PRIV_ASSERT(start == self->fNext);
  696.     FW_PRIV_ASSERT(bytesWritten <= self->fLimit - self->fNext);
  697.     self->fNext += bytesWritten;
  698. }
  699.  
  700.  
  701.